home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / nntp1.5 / part06 < prev    next >
Encoding:
Internet Message Format  |  1988-04-19  |  53.7 KB

  1. Subject:  v14i052:  Network News Transfer Protocol, version 1.5, Part06/09
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Phil Lapsley <phil@ucbvax.berkeley.edu>
  7. Posting-number: Volume 14, Issue 52
  8. Archive-name: nntp1.5/part06
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 6 (of 9)."
  17. # Contents:  ./CHANGES ./common/clientlib.c ./server/newnews.c
  18. #   ./xfer/nntpxfer.c ./xmit/remote.c
  19. # Wrapped by rsalz@fig.bbn.com on Tue Apr 19 18:16:45 1988
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f './CHANGES' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'./CHANGES'\"
  23. else
  24. echo shar: Extracting \"'./CHANGES'\" \(9242 characters\)
  25. sed "s/^X//" >'./CHANGES' <<'END_OF_FILE'
  26. X
  27. X    This file describes the changes which have been made in NNTP
  28. since the initial release.  Individuals who either reported or
  29. inspired the bug/bug fix are in square brackets.
  30. X
  31. X1.5    February 26, 1988
  32. X
  33. X    New top level Makefile.  [Casey Leedom, casey@lll-crg.llnl.gov]
  34. X
  35. X    Now using strcasecmp/strncasecmp instead of streql/strneql.
  36. X    Due credit is given to the University of California at [sic]
  37. X    Berkeley for the use of this software.  :-)
  38. X
  39. X    Combined common/response_codes.h and common/rfc977.h into
  40. X    common/nntp.h.
  41. X
  42. X    Better fix for getifnetmask ioctl returning 0 netmask.
  43. X
  44. X    Patch to Configure to handle domains for non-portable code.
  45. X    [Brad Smith, brad@saturn.ucsc.edu]
  46. X
  47. X    New version of nntpxmit with article retransmission.
  48. X    [Erik Fair, fair@ucbarpa.Berkeley.EDU].
  49. X
  50. X    System V compatability; will now compile on Hockey-Pux (HPUX).  
  51. X    [Stan Barber, sob%soma.tmc.edu@tmc.edu]
  52. X
  53. X    EXCELAN TCP support.  [Stan Barber, sob%soma.tmc.edu@tmc.edu]
  54. X
  55. X    server/subnet.c now supports compiled-in netmasks.
  56. X    This is useful if you want subnet support on machines
  57. X    that don't have the necessary ioctls for determining
  58. X    network masks on a per-interface basis.
  59. X
  60. X    Fake syslog support included for real this time.
  61. X
  62. X1.4    October 15, 1987
  63. X
  64. X    Reorganized documentation directory.  Thanks for the
  65. X    extraction stuff, Stan.  [Stan Barber, sob%%soma.uucp@rice.edu]
  66. X
  67. X    Added transfer timeouts.  [Steve Schoch, schoch@ames.arpa]
  68. X
  69. X    Fixed a problem with IHAVE which allowed a remote machine to
  70. X    repeatedly feed you articles that you expired (although all
  71. X    you'd do with them is throw them away).
  72. X    [Fred Avolio, avolio@decuac.dec.com]
  73. X
  74. X    DECNet support (see server/dnet_access.c and common/clientlib.c).
  75. X        [Matt Thomas, thomas%syrah.dec@decwrl.dec.com]
  76. X
  77. X    Fixed serious joe code in distribution checks in NEWNEWS.
  78. X
  79. X    NEWNEWS statistics.
  80. X
  81. X    Newsgroup security.
  82. X
  83. X    Performance enhancements (about 2x better for article xfers).
  84. X
  85. X    xhdr command added to improve performance on subject searches.
  86. X
  87. X    Compiled-in server name no longer supported.
  88. X
  89. X    common/clientlib.c/getserverbyfile() now looks at the
  90. X    environment variable NNTPSERVER before checking the file.
  91. X
  92. X    inews/inews.c now limits .signature files to MAX_SIGNATURE lines.
  93. X
  94. X    server/misc.c/spawn() now returns the error output of rnews/inews
  95. X    alone with the posting failed code.  This is in turn printed by
  96. X    inews/inews.c so the user has some idea of why his article wasn't
  97. X    accepted.
  98. X
  99. X    rn patches now for patchlevel #40
  100. X        Bug fix: rrn no longer leaves droppings in /tmp
  101. X        "Skipping unavailable article" problems fixed
  102. X        Support for 4.3 TIOCGWINSZ ioctl [sam@okeeffe.berkeley.edu]
  103. X        Configure asks for domains
  104. X        Pnews/Rnmail understand hostnames with .'s in them.
  105. X        Makefile fixes [harvard!lownlab!kiely]
  106. X
  107. X    PYRAMID #defines removed, as it is all being done by default now.
  108. X
  109. X    inews/inews.c now exits 0, since before it had a random exit
  110. X    status, causing pyramids to choke.  [forys@boulder.colorado.edu]
  111. X
  112. X    server/server.c now logs user/system/elapsed time as floats
  113. X    instead of ints.  [rick@seismo.css.gov]
  114. X
  115. X    server/ihave.c no longer logs every message id transfered but
  116. X    instead keeps statistics which are logged at the end.
  117. X    [rick@seismo.css.gov]
  118. X
  119. X    server/serve.c now times out after TIMEOUT seconds of idleness.
  120. X
  121. X    server/access.c converts remote hostname to lower case
  122. X    when logging, in case you have a nameserver which is helping you.
  123. X
  124. X    server/misc.c/getartbyid now reports message-id's when
  125. X    it encounters a malformed line in the history file.
  126. X    [gds@spam.istc.sri.com]
  127. X
  128. X    inews/inews.c had an uninitialized variable, which
  129. X    could cause trouble.  [jwp%chem@sdcsvax.ucsd.edu]
  130. X
  131. X    common/clientlib.c now understands 4.3 nameserver
  132. X    multiple addresses, and tries them all before
  133. X    giving up.
  134. X
  135. X    common/clientlib.c has has 2 new functions:
  136. X    "getserverbyfile" opens a given file and returns
  137. X    the name of the server given in the file to use
  138. X    for news.  "handle_server_response" prints informative
  139. X    messages based on the initial connection response code.
  140. X
  141. X    server/access.c now is case insensitive when checking
  142. X    for host read/xfer permissions.
  143. X
  144. X    server/misc.c/spawn didn't check for a closed connection
  145. X    while receiving input from client.  As a result, truncated
  146. X    news articles could be received.
  147. X
  148. X    server/newnews.c had a printf which was missing an
  149. X    argument.  [louie@trantor.umd.edu]
  150. X
  151. X    Added fake syslog facility to server.  Code is in
  152. X    server/fakesyslog.c.  [mckenny@sri-unix.arpa]
  153. X
  154. X    Fixed length argument to accept() in server/main.c
  155. X    [mckenny@sri-unix.arpa]
  156. X
  157. X    Now uses pipe to rnews so as to get rnews output for debugging.
  158. X    Also chowns temporary file to POSTER's uid and gid.
  159. X    [mckenny@sri-unix.arpa]
  160. X
  161. X    Fixed bugs in server/netaux.c to close syslog fd.
  162. X    [mckenny@sri-unix.arpa]
  163. X
  164. X    Made bcopy() standard in server/misc.c  [kre@munnari.OZ]
  165. X
  166. X    Documentation changes to make certain things about client
  167. X    installation clearer.  [munnari!charlie.oz!craig]
  168. X
  169. X1.3    30 June 1986
  170. X
  171. X    rrn is no longer included as complete source, but
  172. X    rather as a set of context diffs and a program to
  173. X    apply them to your rn source.  Many thanks go to
  174. X    Gene Spafford for an outstanding job doing this.
  175. X    [spaf@gatech.csnet]
  176. X
  177. X    The dreaded kill/save bug is fixed; rn was passing
  178. X    /bin/sh too many open file descriptors.  Thanks and a tip of the
  179. X    proverbial hat to Chris Maio!  Change to rrn/util.c.
  180. X    [chris@columbia.edu]    
  181. X
  182. X    Fixed a bug in rrn/artio.c which caused an assertion
  183. X    failure on line 114 of artio.c; artopen was returning
  184. X    Nullfp without closing the fp associated with the
  185. X    bogus article.  [genrad!ens@eddie.mit.edu, beorn@ic.berkeley.edu]
  186. X
  187. X    Added #define PYRAMID in common/conf.h, added some
  188. X    #ifdef PYRAMID code in server/misc.c to deal with
  189. X    Pyramids not initializing static data to 0, as well
  190. X    as an fseek problem.  [spaf@gatech.CSNET]
  191. X
  192. X    Another wait bug fixed in spawn() in server/misc.c.
  193. X
  194. X    Added a required \r in post.c.
  195. X
  196. X    Added signal(SIGCHLD, SIG_IGN) to server/serve.c,
  197. X    to fix exit status problem with ALONE defined.
  198. X
  199. X    Statistics logging now returns sum of the nntpd and
  200. X    its children for process time.  server/main.c
  201. X    [fair@ucbarpa.berkeley.edu]
  202. X
  203. X    Subnet support for access file finally added.
  204. X    server/subnet.c added, common/conf.h now has
  205. X    #defines for SUBNET, DAMAGED_NETMASK.
  206. X
  207. X    inews/inews.c now generates a from line with the UUCP
  208. X    name instead of always using gethostname().  common/conf.h
  209. X    changed to add #defines for UUNAME, GHNAME.
  210. X    [jwang@atrp.mit.edu]
  211. X
  212. X    Added LIBS to Makefile. [soma!sob@rice.edu]
  213. X
  214. X1.2c    17 May 1986
  215. X
  216. X    Support for Masscomp added (#define MASSCOMP in ../common/conf.h).
  217. X    [soma!sob@rice.edu]
  218. X
  219. X    Syslog output now requires SYSLOG to be defined in ../common/conf.h.
  220. X    This is handy on systems which, for some reason or another,
  221. X    don't have syslog.  [soma!sob@rice.edu]
  222. X
  223. X    server/post.c had arguments reversed in a printf.  [salex@rice.edu]
  224. X
  225. X    rrn/common.h had PIPESAVER misdefined. [cspencer@bbncc5.arpa]
  226. X
  227. X    server/group.c was missing a \r in a printf.  [lear@rutgers.edu]
  228. X
  229. X    xmit/nntpxmit.c is a new version.  Highlights include
  230. X    improved error reactions and logging info.  [fair@ucbarpa.berkeley.edu]
  231. X
  232. X    xmit/nntpsend is a shell script for sending news via nntp
  233. X    in a sane manner, with locking.  [pleasant@topaz.rutgers.edu,
  234. X    fair@ucbarpa.berkeley.edu]  The locking mechanism is provided
  235. X    courtesy of Mr. Fair's "shlock.c", in xmit/shlock.c.
  236. X
  237. X    support/nntp_awk produces weekly reports from the nntp server
  238. X    logging output.  [fair@ucbarpa.berkeley.edu]
  239. X
  240. X    Makefile (in this directory) would do a "make install" as
  241. X    the default action; it now prints a helpful message.
  242. X    [arnold@cgl.ucsf.edu]
  243. X
  244. X    server/Makefile and support/Makefile had needless dependencies
  245. X    in them; if you didn't do a make depend, you'd have problems
  246. X    on a 4.2 system.  The server and support stuff now depend only
  247. X    on their own .h files.  [arnold@cgl.ucsf.edu]
  248. X
  249. X1.2b    13 April 1986
  250. X
  251. X    common/clientlib.c stupidly had some debugging printfs
  252. X    enabled.
  253. X
  254. X    rrn/{artio.c,head.c} had sprintf("... %d", foo) where "foo"
  255. X    was a long.  %d -> %ld.  [cspencer@bbncc5.arpa]
  256. X
  257. X    server/time.c had an order of evaluation problem in the
  258. X    macro "twodigtoi".  [fletcher@tzec.cs.utexas.edu, among others.]
  259. X
  260. X    server/common.h included <dbm.h> if DBM was defined,
  261. X    caused multiply-defined NULL's.  [cda@opal.berkeley.edu,
  262. X    pleasant@topaz.rutgers.edu, among others.]
  263. X
  264. X    server/active.c would lose because variable "i" would be
  265. X    at the end of the group array if it was called on a timer
  266. X    interrupt.  "i" now set to zero properly.  This only occurs
  267. X    if FASTFORK is defined.  [cda@opal.berkeley.edu]
  268. X
  269. X1.2a    20 March 1986
  270. X
  271. X    common/conf.h defined MAX_GROUPS as 300; this was too low on
  272. X    some machines.  Upped to 450.  [solex@rice.edu, beorn@ic.berkeley.edu]
  273. X
  274. X    rrn/Makefile.sh had .c instead of .o for OBJS and SRCS
  275. X    respectively.  Also had cc -o ../common/clientlib.o (see below).
  276. X
  277. X    inews/inews.c had (char *) 0 for gets(), which made SUN's upset.
  278. X    Changed to simply NULL. [brian@sdcsvax.ucsd.edu]
  279. X
  280. X    inews/Makefile had cc -o ../common/clientlib.o which some
  281. X    machines don't do.  [brian@sdcsvax.ucsd.edu]
  282. X
  283. X    common/clientlib.c has "untp" instead of "nntp".
  284. X
  285. X    server/active.c made more robust about reading active file
  286. X    if active file is longer than MAX_GROUPS.
  287. X
  288. X    server/common.h included common/conf.h after checking for
  289. X    DBM, which caused some problems.  [soma!sob@rice.edu]
  290. X
  291. X1.2    15 March 1986
  292. X
  293. X    Released.
  294. END_OF_FILE
  295. if test 9242 -ne `wc -c <'./CHANGES'`; then
  296.     echo shar: \"'./CHANGES'\" unpacked with wrong size!
  297. fi
  298. # end of './CHANGES'
  299. fi
  300. if test -f './common/clientlib.c' -a "${1}" != "-c" ; then 
  301.   echo shar: Will not clobber existing file \"'./common/clientlib.c'\"
  302. else
  303. echo shar: Extracting \"'./common/clientlib.c'\" \(10189 characters\)
  304. sed "s/^X//" >'./common/clientlib.c' <<'END_OF_FILE'
  305. X#ifndef lint
  306. static char    *sccsid = "@(#)clientlib.c    1.9    (Berkeley) 2/25/88";
  307. X#endif
  308. X
  309. X/*
  310. X * NNTP client routines.
  311. X */
  312. X
  313. X/*
  314. X * Include configuration parameters only if we're made in the nntp tree.
  315. X */
  316. X
  317. X#ifdef NNTPSRC
  318. X#include "../common/conf.h"
  319. X#endif NNTPSRC
  320. X
  321. X#include <stdio.h>
  322. X#include <sys/types.h>
  323. X#include <sys/socket.h>
  324. X#include <netinet/in.h>
  325. X#ifndef EXCELAN
  326. X# include <netdb.h>
  327. X#endif not EXCELAN
  328. X
  329. X#ifdef USG
  330. X# define    index    strchr
  331. X#endif USG
  332. X
  333. X#ifdef EXCELAN
  334. X# define    IPPORT_NNTP    119
  335. X#endif
  336. X
  337. X#ifdef DECNET
  338. X#include <netdnet/dn.h>
  339. X#include <netdnet/dnetdb.h>
  340. X#endif DECNET
  341. X
  342. X#include "nntp.h"
  343. X
  344. FILE    *ser_rd_fp = NULL;
  345. FILE    *ser_wr_fp = NULL;
  346. X
  347. X/*
  348. X * getserverbyfile    Get the name of a server from a named file.
  349. X *            Handle white space and comments.
  350. X *            Use NNTPSERVER environment variable if set.
  351. X *
  352. X *    Parameters:    "file" is the name of the file to read.
  353. X *
  354. X *    Returns:    Pointer to static data area containing the
  355. X *            first non-ws/comment line in the file.
  356. X *            NULL on error (or lack of entry in file).
  357. X *
  358. X *    Side effects:    None.
  359. X */
  360. X
  361. char *
  362. getserverbyfile(file)
  363. char    *file;
  364. X{
  365. X    register FILE    *fp;
  366. X    register char    *cp;
  367. X    static char    buf[256];
  368. X    char        *index();
  369. X    char        *getenv();
  370. X    char        *strcpy();
  371. X
  372. X    if (cp = getenv("NNTPSERVER")) {
  373. X        (void) strcpy(buf, cp);
  374. X        return (buf);
  375. X    }
  376. X
  377. X    if (file == NULL)
  378. X        return (NULL);
  379. X
  380. X    fp = fopen(file, "r");
  381. X    if (fp == NULL)
  382. X        return (NULL);
  383. X
  384. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  385. X        if (*buf == '\n' || *buf == '#')
  386. X            continue;
  387. X        cp = index(buf, '\n');
  388. X        if (cp)
  389. X            *cp = '\0';
  390. X        (void) fclose(fp);
  391. X        return (buf);
  392. X    }
  393. X
  394. X    (void) fclose(fp);
  395. X    return (NULL);             /* No entry */
  396. X}
  397. X
  398. X
  399. X/*
  400. X * server_init  Get a connection to the remote news server.
  401. X *
  402. X *    Parameters:    "machine" is the machine to connect to.
  403. X *
  404. X *    Returns:    -1 on error
  405. X *            server's initial response code on success.
  406. X *
  407. X *    Side effects:    Connects to server.
  408. X *            "ser_rd_fp" and "ser_wr_fp" are fp's
  409. X *            for reading and writing to server.
  410. X */
  411. X
  412. server_init(machine)
  413. char    *machine;
  414. X{
  415. X    int    sockt_rd, sockt_wr;
  416. X    char    line[256];
  417. X    char    *index();
  418. X#ifdef DECNET
  419. X    char    *cp;
  420. X
  421. X    cp = index(machine, ':');
  422. X
  423. X    if (cp && cp[1] == ':') {
  424. X        *cp = '\0';
  425. X        sockt_rd = get_dnet_socket(machine);
  426. X    } else
  427. X        sockt_rd = get_tcp_socket(machine);
  428. X#else
  429. X    sockt_rd = get_tcp_socket(machine);
  430. X#endif
  431. X
  432. X    if (sockt_rd < 0)
  433. X        return (-1);
  434. X
  435. X    /*
  436. X     * Now we'll make file pointers (i.e., buffered I/O) out of
  437. X     * the socket file descriptor.  Note that we can't just
  438. X     * open a fp for reading and writing -- we have to open
  439. X     * up two separate fp's, one for reading, one for writing.
  440. X     */
  441. X
  442. X    if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) {
  443. X        perror("server_init: fdopen #1");
  444. X        return (-1);
  445. X    }
  446. X
  447. X    sockt_wr = dup(sockt_rd);
  448. X    if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) {
  449. X        perror("server_init: fdopen #2");
  450. X        ser_rd_fp = NULL;        /* from above */
  451. X        return (-1);
  452. X    }
  453. X
  454. X    /* Now get the server's signon message */
  455. X
  456. X    (void) get_server(line, sizeof(line));
  457. X    return (atoi(line));
  458. X}
  459. X
  460. X
  461. X/*
  462. X * get_tcp_socket -- get us a socket connected to the news server.
  463. X *
  464. X *    Parameters:    "machine" is the machine the server is running on.
  465. X *
  466. X *    Returns:    Socket connected to the news server if
  467. X *            all is ok, else -1 on error.
  468. X *
  469. X *    Side effects:    Connects to server.
  470. X *
  471. X *    Errors:        Printed via perror.
  472. X */
  473. X
  474. get_tcp_socket(machine)
  475. char    *machine;
  476. X{
  477. X    int    s;
  478. X    struct    sockaddr_in sin;
  479. X#ifndef EXCELAN
  480. X    struct    servent *getservbyname(), *sp;
  481. X    struct    hostent *gethostbyname(), *hp;
  482. X#ifdef h_addr
  483. X    int    x = 0;
  484. X    register char **cp;
  485. X#endif h_addr
  486. X
  487. X    if ((sp = getservbyname("nntp", "tcp")) ==  NULL) {
  488. X        fprintf(stderr, "nntp/tcp: Unknown service.\n");
  489. X        return (-1);
  490. X    }
  491. X
  492. X    if ((hp = gethostbyname(machine)) == NULL) {
  493. X        fprintf(stderr, "%s: Unknown host.\n", machine);
  494. X        return (-1);
  495. X    }
  496. X
  497. X    bzero((char *) &sin, sizeof(sin));
  498. X    sin.sin_family = hp->h_addrtype;
  499. X    sin.sin_port = sp->s_port;
  500. X#else EXCELAN
  501. X    bzero((char *) &sin, sizeof(sin));
  502. X    sin.sin_family = AF_INET;
  503. X    sin.sin_port = htons(IPPORT_NNTP);
  504. X#endif EXCELAN
  505. X
  506. X    /*
  507. X     * The following is kinda gross.  The name server under 4.3
  508. X     * returns a list of addresses, each of which should be tried
  509. X     * in turn if the previous one fails.  However, 4.2 hostent
  510. X     * structure doesn't have this list of addresses.
  511. X     * Under 4.3, h_addr is a #define to h_addr_list[0].
  512. X     * We use this to figure out whether to include the NS specific
  513. X     * code...
  514. X     */
  515. X
  516. X#ifdef    h_addr
  517. X
  518. X    /* get a socket and initiate connection -- use multiple addresses */
  519. X
  520. X    for (cp = hp->h_addr_list; cp && *cp; cp++) {
  521. X        s = socket(hp->h_addrtype, SOCK_STREAM, 0);
  522. X        if (s < 0) {
  523. X            perror("socket");
  524. X            return (-1);
  525. X        }
  526. X            bcopy(*cp, (char *)&sin.sin_addr, hp->h_length);
  527. X        
  528. X        if (x < 0)
  529. X            fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
  530. X        x = connect(s, (struct sockaddr *)&sin, sizeof (sin));
  531. X        if (x == 0)
  532. X            break;
  533. X                fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
  534. X        perror("");
  535. X        (void) close(s);
  536. X    }
  537. X    if (x < 0) {
  538. X        fprintf(stderr, "giving up...\n");
  539. X        return (-1);
  540. X    }
  541. X#else    /* no name server */
  542. X#ifdef EXCELAN
  543. X    if ((s = rresvport(SO_KEEPALIVE)) < 0)
  544. X    {
  545. X        /* Get the socket */
  546. X        perror("socket");
  547. X        return (-1);
  548. X    }
  549. X    /* set up addr for the connect */
  550. X    sin.sin_addr.s_addr = rhost(machine);
  551. X    if (sin.sin_addr.s_addr < 0){
  552. X        fprintf(stderr, "%s: Unknown host.\n", machine);
  553. X        return (-1);
  554. X    }
  555. X    /* And then connect */
  556. X
  557. X    if (connect(s, &sin) < 0) {
  558. X        perror("connect");
  559. X        (void) close(s);
  560. X        return (-1);
  561. X    }
  562. X#else not EXCELAN
  563. X    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  564. X        perror("socket");
  565. X        return (-1);
  566. X    }
  567. X
  568. X    /* And then connect */
  569. X
  570. X    bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  571. X    if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  572. X        perror("connect");
  573. X        (void) close(s);
  574. X        return (-1);
  575. X    }
  576. X
  577. X#endif not EXCELAN
  578. X#endif
  579. X
  580. X    return (s);
  581. X}
  582. X
  583. X#ifdef DECNET
  584. X/*
  585. X * get_dnet_socket -- get us a socket connected to the news server.
  586. X *
  587. X *    Parameters:    "machine" is the machine the server is running on.
  588. X *
  589. X *    Returns:    Socket connected to the news server if
  590. X *            all is ok, else -1 on error.
  591. X *
  592. X *    Side effects:    Connects to server.
  593. X *
  594. X *    Errors:        Printed via nerror.
  595. X */
  596. X
  597. get_dnet_socket(machine)
  598. char    *machine;
  599. X{
  600. X    int    s, area, node;
  601. X    struct    sockaddr_dn sdn;
  602. X    struct    nodeent *getnodebyname(), *np;
  603. X
  604. X    bzero((char *) &sdn, sizeof(sdn));
  605. X
  606. X    switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) {
  607. X        case 1: 
  608. X            node = area;
  609. X            area = 0;
  610. X        case 2: 
  611. X            node += area*1024;
  612. X            sdn.sdn_add.a_len = 2;
  613. X            sdn.sdn_family = AF_DECnet;
  614. X            sdn.sdn_add.a_addr[0] = node % 256;
  615. X            sdn.sdn_add.a_addr[1] = node / 256;
  616. X            break;
  617. X        default:
  618. X            if ((np = getnodebyname(machine)) == NULL) {
  619. X                fprintf(stderr, 
  620. X                    "%s: Unknown host.\n", machine);
  621. X                return (-1);
  622. X            } else {
  623. X                bcopy(np->n_addr, 
  624. X                    (char *) sdn.sdn_add.a_addr, 
  625. X                    np->n_length);
  626. X                sdn.sdn_add.a_len = np->n_length;
  627. X                sdn.sdn_family = np->n_addrtype;
  628. X            }
  629. X            break;
  630. X    }
  631. X    sdn.sdn_objnum = 0;
  632. X    sdn.sdn_flags = 0;
  633. X    sdn.sdn_objnamel = strlen("NNTP");
  634. X    bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
  635. X
  636. X    if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
  637. X        nerror("socket");
  638. X        return (-1);
  639. X    }
  640. X
  641. X    /* And then connect */
  642. X
  643. X    if (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) {
  644. X        nerror("connect");
  645. X        close(s);
  646. X        return (-1);
  647. X    }
  648. X
  649. X    return (s);
  650. X}
  651. X#endif
  652. X
  653. X
  654. X
  655. X/*
  656. X * handle_server_response
  657. X *
  658. X *    Print some informative messages based on the server's initial
  659. X *    response code.  This is here so inews, rn, etc. can share
  660. X *    the code.
  661. X *
  662. X *    Parameters:    "response" is the response code which the
  663. X *            server sent us, presumably from "server_init",
  664. X *            above.
  665. X *            "server" is the news server we got the
  666. X *            response code from.
  667. X *
  668. X *    Returns:    -1 if the error is fatal (and we should exit).
  669. X *            0 otherwise.
  670. X *
  671. X *    Side effects:    None.
  672. X */
  673. X
  674. handle_server_response(response, server)
  675. int    response;
  676. char    *server;
  677. X{
  678. X    switch (response) {
  679. X    case OK_NOPOST:        /* fall through */
  680. X            printf(
  681. X    "NOTE: This machine does not have permission to post articles.\n");
  682. X        printf(
  683. X    "      Please don't waste your time trying.\n\n");
  684. X
  685. X    case OK_CANPOST:
  686. X        return (0);
  687. X        break;
  688. X
  689. X    case ERR_ACCESS:
  690. X        printf(
  691. X   "This machine does not have permission to use the %s news server.\n",
  692. X        server);
  693. X        return (-1);
  694. X        break;
  695. X
  696. X    default:
  697. X        printf("Unexpected response code from %s news server: %d\n",
  698. X            server, response);
  699. X        return (-1);
  700. X        break;
  701. X    }
  702. X    /*NOTREACHED*/
  703. X}
  704. X
  705. X
  706. X/*
  707. X * put_server -- send a line of text to the server, terminating it
  708. X * with CR and LF, as per ARPA standard.
  709. X *
  710. X *    Parameters:    "string" is the string to be sent to the
  711. X *            server.
  712. X *
  713. X *    Returns:    Nothing.
  714. X *
  715. X *    Side effects:    Talks to the server.
  716. X *
  717. X *    Note:        This routine flushes the buffer each time
  718. X *            it is called.  For large transmissions
  719. X *            (i.e., posting news) don't use it.  Instead,
  720. X *            do the fprintf's yourself, and then a final
  721. X *            fflush.
  722. X */
  723. X
  724. void
  725. put_server(string)
  726. char *string;
  727. X{
  728. X#ifdef DEBUG
  729. X    fprintf(stderr, ">>> %s\n", string);
  730. X#endif
  731. X    fprintf(ser_wr_fp, "%s\r\n", string);
  732. X    (void) fflush(ser_wr_fp);
  733. X}
  734. X
  735. X
  736. X/*
  737. X * get_server -- get a line of text from the server.  Strips
  738. X * CR's and LF's.
  739. X *
  740. X *    Parameters:    "string" has the buffer space for the
  741. X *            line received.
  742. X *            "size" is the size of the buffer.
  743. X *
  744. X *    Returns:    -1 on error, 0 otherwise.
  745. X *
  746. X *    Side effects:    Talks to server, changes contents of "string".
  747. X */
  748. X
  749. get_server(string, size)
  750. char    *string;
  751. int    size;
  752. X{
  753. X    register char *cp;
  754. X    char    *index();
  755. X
  756. X    if (fgets(string, size, ser_rd_fp) == NULL)
  757. X        return (-1);
  758. X
  759. X    if ((cp = index(string, '\r')) != NULL)
  760. X        *cp = '\0';
  761. X    else if ((cp = index(string, '\n')) != NULL)
  762. X        *cp = '\0';
  763. X#ifdef DEBUG
  764. X    fprintf(stderr, "<<< %s\n", string);
  765. X#endif
  766. X
  767. X    return (0);
  768. X}
  769. X
  770. X
  771. X/*
  772. X * close_server -- close the connection to the server, after sending
  773. X *        the "quit" command.
  774. X *
  775. X *    Parameters:    None.
  776. X *
  777. X *    Returns:    Nothing.
  778. X *
  779. X *    Side effects:    Closes the connection with the server.
  780. X *            You can't use "put_server" or "get_server"
  781. X *            after this routine is called.
  782. X */
  783. X
  784. void
  785. close_server()
  786. X{
  787. X    char    ser_line[256];
  788. X
  789. X    if (ser_wr_fp == NULL || ser_rd_fp == NULL)
  790. X        return;
  791. X
  792. X    put_server("QUIT");
  793. X    (void) get_server(ser_line, sizeof(ser_line));
  794. X
  795. X    (void) fclose(ser_wr_fp);
  796. X    (void) fclose(ser_rd_fp);
  797. X}
  798. X
  799. X#ifdef USG
  800. bzero(p, l)
  801. X    register char    *p;
  802. X    register int    l;
  803. X{
  804. X    while (l-- > 0)
  805. X        *p++ = 0;
  806. X}
  807. X#endif USG
  808. END_OF_FILE
  809. if test 10189 -ne `wc -c <'./common/clientlib.c'`; then
  810.     echo shar: \"'./common/clientlib.c'\" unpacked with wrong size!
  811. fi
  812. # end of './common/clientlib.c'
  813. fi
  814. if test -f './server/newnews.c' -a "${1}" != "-c" ; then 
  815.   echo shar: Will not clobber existing file \"'./server/newnews.c'\"
  816. else
  817. echo shar: Extracting \"'./server/newnews.c'\" \(10834 characters\)
  818. sed "s/^X//" >'./server/newnews.c' <<'END_OF_FILE'
  819. X#ifndef lint
  820. static char    *sccsid = "@(#)newnews.c    1.19    (Berkeley) 2/6/88";
  821. X#endif
  822. X
  823. X#include "common.h"
  824. X#include "time.h"
  825. X
  826. X#ifdef LOG
  827. int    nn_told = 0;
  828. int    nn_took = 0;
  829. X#endif
  830. X
  831. X
  832. X/*
  833. X * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
  834. X *
  835. X * Return the message-id's of any news articles past
  836. X * a certain date and time, within the specified distributions.
  837. X *
  838. X */
  839. X
  840. newnews(argc, argv)
  841. X    register int    argc;
  842. X    char        *argv[];
  843. X{
  844. X    register char    *cp, *ngp;
  845. X    char        *key;
  846. X    char        datebuf[32];
  847. X    char        line[MAXBUFLEN];
  848. X    char        **distlist, **histlist;
  849. X    static char    **nglist;
  850. X    int        distcount, ngcount, histcount;
  851. X    int        all;
  852. X    FILE        *fp;
  853. X    long        date;
  854. X    long        dtol();
  855. X    char        *ltod();
  856. X#ifdef USG
  857. X    FILE        *tmplst;
  858. X    int        i;
  859. X    char        *tmpfile;
  860. X#endif USG
  861. X
  862. X    if (argc < 4) {
  863. X        printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>].\r\n",
  864. X            ERR_CMDSYN);
  865. X        (void) fflush(stdout);
  866. X        return;
  867. X    }
  868. X
  869. X#ifdef LOG
  870. X    sprintf(line, "%s newnews %s %s %s %s %s",
  871. X        hostname,
  872. X        argv[1],
  873. X        argv[2],
  874. X        argv[3],
  875. X        (argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
  876. X        (argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
  877. X    syslog(LOG_INFO, line);
  878. X#endif
  879. X
  880. X    all = (argv[1][0] == '*' && argv[1][1] == '\0');
  881. X    if (!all) {
  882. X        ngcount = get_nglist(&nglist, argv[1]);
  883. X        if (ngcount == 0) {
  884. X            printf("%d Bogus newsgroup specifier: %s\r\n",
  885. X                ERR_CMDSYN, argv[1]);
  886. X            (void) fflush(stdout);
  887. X            return;
  888. X        }
  889. X    }
  890. X
  891. X    /*        YYMMDD            HHMMSS    */
  892. X    if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
  893. X        printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
  894. X            ERR_CMDSYN);
  895. X        (void) fflush(stdout);
  896. X        return;
  897. X    }
  898. X
  899. X    (void) strcpy(datebuf, argv[2]);
  900. X    (void) strcat(datebuf, argv[3]);
  901. X
  902. X    argc -= 4;
  903. X    argv += 4;
  904. X
  905. X    /*
  906. X     * Flame on.  The history file is not stored in GMT, but
  907. X     * in local time.  So we have to convert GMT to local time
  908. X     * if we're given GMT, otherwise we need only chop off the
  909. X     * the seconds.  Such braindamage.
  910. X     */
  911. X
  912. X    key = datebuf;        /* Unless they specify GMT */
  913. X
  914. X    if (argc > 0) {
  915. X        if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
  916. X            date = dtol(datebuf);
  917. X            if (date < 0) {
  918. X                printf("%d Invalid date specification.\r\n",
  919. X                    ERR_CMDSYN);
  920. X                (void) fflush(stdout);
  921. X                return;
  922. X            }
  923. X            date = gmt_to_local(date);
  924. X            key = ltod(date);
  925. X            ++argv;
  926. X            --argc;
  927. X        }
  928. X    }
  929. X
  930. X    /* So, key now points to the local time, but we need to zap secs */
  931. X
  932. X    key[10] = '\0';
  933. X
  934. X    distcount = 0;
  935. X    if (argc > 0) {
  936. X        distcount = get_distlist(&distlist, *argv);
  937. X        if (distcount < 0) {
  938. X            printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
  939. X                *argv);
  940. X            (void) fflush(stdout);
  941. X            return;
  942. X        }
  943. X    }
  944. X
  945. X#ifdef USG
  946. X    if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
  947. X        (tmplst = fopen(tmpfile, "w+")) == NULL) {
  948. X    printf("%d Cannot process history file.\r\n", ERR_FAULT);
  949. X    (void) fflush(stdout);
  950. X    return;
  951. X    }
  952. X
  953. X    for (i = 0; i < 9; i++) {
  954. X        sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
  955. X#endif USG
  956. X
  957. X    fp = fopen(historyfile, "r");
  958. X    if (fp == NULL) {
  959. X#ifdef SYSLOG
  960. X        syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
  961. X#endif
  962. X#ifndef USG
  963. X        printf("%d Cannot open history file.\r\n", ERR_FAULT);
  964. X        (void) fflush(stdout);
  965. X        return;
  966. X#else USG
  967. X        continue;
  968. X#endif USG
  969. X    }
  970. X
  971. X#ifndef USG
  972. X    printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
  973. X#endif not USG
  974. X
  975. X    if (seekuntil(fp, key, line, sizeof (line)) < 0) {
  976. X#ifndef USG
  977. X        printf(".\r\n");
  978. X        (void) fflush(stdout);
  979. X#endif not USG
  980. X        (void) fclose(fp);
  981. X#ifndef USG
  982. X        return;
  983. X#else USG
  984. X        continue;
  985. X#endif USG
  986. X    }
  987. X
  988. X/*
  989. X * History file looks like:
  990. X *
  991. X * <1569@emory.UUCP>    01/22/86 09:19    net.micro.att/899 ucb.general/2545 
  992. X *             ^--tab            ^--tab         ^--space         ^sp\0
  993. X * Sometimes the newsgroups are missing; we try to be robust and
  994. X * ignore such bogosity.  We tackle this by our usual parse routine,
  995. X * and break the list of articles in the history file into an argv
  996. X * array with one newsgroup per entry.
  997. X */
  998. X
  999. X    do {
  1000. X        if ((cp = index(line, '\t')) == NULL)
  1001. X            continue;
  1002. X
  1003. X        if ((ngp = index(cp+1, '\t')) == NULL)    /* 2nd tab */
  1004. X            continue;
  1005. X        ++ngp;            /* Points at newsgroup list */
  1006. X        if (*ngp == '\n')
  1007. X            continue;
  1008. X        histcount = get_histlist(&histlist, ngp);
  1009. X        if (histcount == 0)
  1010. X            continue;
  1011. X
  1012. X        /*
  1013. X         * For each newsgroup on this line in the history
  1014. X         * file, check it against the newsgroup names we're given.
  1015. X         * If it matches, then see if we're hacking distributions.
  1016. X         * If so, open the file and match the distribution line.
  1017. X         */
  1018. X
  1019. X        if (!all)
  1020. X            if (!ngmatch(restreql, 0, nglist, ngcount,
  1021. X                histlist, histcount))
  1022. X                continue;
  1023. X
  1024. X        if (distcount)
  1025. X            if (!distmatch(distlist, distcount, histlist, histcount))
  1026. X                continue;
  1027. X
  1028. X        *cp = '\0';
  1029. X#ifdef USG
  1030. X        fputs(line, tmplst);
  1031. X        fputc('\n', tmplst);
  1032. X#else not USG
  1033. X        putline(line);
  1034. X#endif not USG
  1035. X#ifdef LOG
  1036. X        nn_told++;
  1037. X#endif
  1038. X    } while (fgets(line, sizeof(line), fp) != NULL);
  1039. X
  1040. X#ifndef USG
  1041. X    putchar('.');
  1042. X    putchar('\r');
  1043. X    putchar('\n');
  1044. X    (void) fflush(stdout);
  1045. X#endif
  1046. X    (void) fclose(fp);
  1047. X#ifdef USG
  1048. X    }
  1049. X    printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
  1050. X    rewind(tmplst);
  1051. X    while (fgets(line, sizeof(line), tmplst) != NULL)
  1052. X            putline(line);
  1053. X    putchar('.');
  1054. X    putchar('\r');
  1055. X    putchar('\n');
  1056. X    (void) fflush(stdout);
  1057. X    (void) fclose(tmplst);
  1058. X    (void) unlink(tmpfile);
  1059. X#endif USG
  1060. X}
  1061. X
  1062. X
  1063. X/*
  1064. X * seekuntil -- seek through the history file looking for
  1065. X * a line with date "key".  Get that line, and return.
  1066. X *
  1067. X *    Parameters:    "fp" is the active file.
  1068. X *            "key" is the date, in form YYMMDDHHMM (no SS)
  1069. X *            "line" is storage for the first line we find.
  1070. X *
  1071. X *    Returns:    -1 on error, 0 otherwise.
  1072. X *
  1073. X *    Side effects:    Seeks in history file, modifies line.
  1074. X */
  1075. X
  1076. seekuntil(fp, key, line, linesize)
  1077. X    FILE        *fp;
  1078. X    char        *key;
  1079. X    char        *line;
  1080. X    int        linesize;
  1081. X{
  1082. X    char        datetime[32];
  1083. X    register int    c;
  1084. X    register long    top, bot, mid;
  1085. X
  1086. X    bot = 0;
  1087. X    (void) fseek(fp, 0L, 2);
  1088. X    top = ftell(fp);
  1089. X    for(;;) {
  1090. X        mid = (top+bot)/2;
  1091. X        (void) fseek(fp, mid, 0);
  1092. X        do {
  1093. X            c = getc(fp);
  1094. X            mid++;
  1095. X        } while (c != EOF && c!='\n');
  1096. X        if (!getword(fp, datetime, line, linesize)) {
  1097. X            return (-1);
  1098. X        }
  1099. X        switch (compare(key, datetime)) {
  1100. X        case -2:
  1101. X        case -1:
  1102. X        case 0:
  1103. X            if (top <= mid)
  1104. X                break;
  1105. X            top = mid;
  1106. X            continue;
  1107. X        case 1:
  1108. X        case 2:
  1109. X            bot = mid;
  1110. X            continue;
  1111. X        }
  1112. X        break;
  1113. X    }
  1114. X    (void) fseek(fp, bot, 0);
  1115. X    while(ftell(fp) < top) {
  1116. X        if (!getword(fp, datetime, line, linesize)) {
  1117. X            return (-1);
  1118. X        }
  1119. X        switch(compare(key, datetime)) {
  1120. X        case -2:
  1121. X        case -1:
  1122. X        case 0:
  1123. X            break;
  1124. X        case 1:
  1125. X        case 2:
  1126. X            continue;
  1127. X        }
  1128. X        break;
  1129. X    }
  1130. X
  1131. X    return (0);
  1132. X}
  1133. X
  1134. X
  1135. compare(s, t)
  1136. X    register char *s, *t;
  1137. X{
  1138. X    for (; *s == *t; s++, t++)
  1139. X        if (*s == 0)
  1140. X            return(0);
  1141. X    return (*s == 0 ? -1:
  1142. X        *t == 0 ? 1:
  1143. X        *s < *t ? -2:
  1144. X        2);
  1145. X}
  1146. X
  1147. X
  1148. getword(fp, w, line, linesize)
  1149. X    FILE        *fp;
  1150. X    register char    *w;
  1151. X    char        *line;
  1152. X    int        linesize;
  1153. X{
  1154. X    register char    *cp;
  1155. X
  1156. X    if (fgets(line, linesize, fp) == NULL)
  1157. X        return (0);
  1158. X    if (cp = index(line, '\t')) {
  1159. X/*
  1160. X * The following gross hack is present because the history file date
  1161. X * format is braindamaged.  They like "mm/dd/yy hh:mm", which is useless
  1162. X * for relative comparisons of dates using something like atoi() or
  1163. X * strcmp.  So, this changes their format into yymmddhhmm.  Sigh.
  1164. X *
  1165. X * 12345678901234    ("x" for cp[x])
  1166. X * mm/dd/yy hh:mm     (their lousy representation)
  1167. X * yymmddhhmm        (our good one)
  1168. X * 0123456789        ("x" for w[x])
  1169. X */
  1170. X        *cp = '\0';
  1171. X        (void) strncpy(w, cp+1, 15);
  1172. X        w[0] = cp[7];        /* Years */
  1173. X        w[1] = cp[8];
  1174. X        w[2] = cp[1];        /* Months */
  1175. X        w[3] = cp[2];
  1176. X        w[4] = cp[4];        /* Days */
  1177. X        w[5] = cp[5];
  1178. X        w[6] = cp[10];        /* Hours */
  1179. X        w[7] = cp[11];
  1180. X        w[8] = cp[13];        /* Minutes */
  1181. X        w[9] = cp[14];
  1182. X        w[10] = '\0';
  1183. X    } else
  1184. X        w[0] = '\0';
  1185. X    return (1);
  1186. X}
  1187. X
  1188. X
  1189. X/*
  1190. X * distmatch -- see if a file matches a set of distributions.
  1191. X * We have to do this by (yech!) opening the file, finding
  1192. X * the Distribution: line, if it has one, and seeing if the
  1193. X * things match.
  1194. X *
  1195. X *    Parameters:    "distlist" is the distribution list
  1196. X *            we want.
  1197. X *            "distcount" is the count of distributions in it.
  1198. X *            "grouplist" is the list of groups (articles)
  1199. X *            for this line of the history file.  Note that
  1200. X *            this isn't quite a filename.
  1201. X *            "groupcount" is the count of groups in it.
  1202. X *            
  1203. X *    Returns:    1 if the article is in the given distribution.
  1204. X *            0 otherwise.
  1205. X */
  1206. X
  1207. distmatch(distlist, distcount, grouplist, groupcount)
  1208. X    char        *distlist[];
  1209. X    int        distcount;
  1210. X    char        *grouplist[];
  1211. X    int        groupcount;
  1212. X{
  1213. X    register char    c;
  1214. X    register char    *cp;
  1215. X    register FILE    *fp;
  1216. X    register int    i, j;
  1217. X    char        buf[MAXBUFLEN];
  1218. X
  1219. X    (void) strcpy(buf, spooldir);
  1220. X    (void) strcat(buf, "/");
  1221. X    (void) strcat(buf, grouplist[0]);
  1222. X
  1223. X    for (cp = buf; *cp; cp++)
  1224. X        if (*cp == '.')
  1225. X            *cp = '/';
  1226. X
  1227. X    fp = fopen(buf, "r");
  1228. X    if (fp == NULL) {
  1229. X#ifdef SYSLOG
  1230. X        syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
  1231. X#endif
  1232. X        return (0);
  1233. X    }
  1234. X
  1235. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  1236. X        if ((c = buf[0]) == '\n')        /* End of header */
  1237. X            break;
  1238. X        if (c != 'd' && c != 'D')
  1239. X            continue;
  1240. X        cp = index(cp + 1, '\n');
  1241. X        if (cp)
  1242. X            *cp = '\0';
  1243. X        cp = index(buf, ':');
  1244. X        if (cp == NULL)
  1245. X            continue;
  1246. X        *cp = '\0';
  1247. X        if (!strcasecmp(buf, "distribution")) {
  1248. X            for (i = 0; i < distcount; ++i) {
  1249. X                if (!strcasecmp(cp + 2, distlist[i])) {
  1250. X                    (void) fclose(fp);
  1251. X                    return (1);
  1252. X                }
  1253. X            }
  1254. X            (void) fclose(fp);
  1255. X            return (0);
  1256. X        }
  1257. X    }
  1258. X
  1259. X    (void) fclose(fp);
  1260. X
  1261. X    /*
  1262. X     * We've finished the header with no distribution field.
  1263. X     * So we'll assume that the distribution is the characters
  1264. X     * up to the first dot in the newsgroup name.
  1265. X     */
  1266. X
  1267. X    for (i = 0; i < groupcount; i++) {
  1268. X        cp = index(grouplist[i], '.');
  1269. X        if (cp)
  1270. X            *cp = '\0';
  1271. X        for (j = 0; j < distcount; j++)
  1272. X            if (!strcasecmp(grouplist[i], distlist[j]))
  1273. X                return (1);
  1274. X    }
  1275. X        
  1276. X    return (0);
  1277. X}
  1278. X
  1279. X
  1280. X/*
  1281. X * get_histlist -- return a nicely set up array of newsgroups
  1282. X * (actually, net.foo.bar/article_num) along with a count.
  1283. X *
  1284. X *    Parameters:        "array" is storage for our array,
  1285. X *                set to point at some static data.
  1286. X *                "list" is the history file newsgroup list.
  1287. X *
  1288. X *    Returns:        Number of group specs found.
  1289. X *
  1290. X *    Side effects:        Changes static data area.
  1291. X */
  1292. X
  1293. get_histlist(array, list)
  1294. X    char        ***array;
  1295. X    char        *list;
  1296. X{
  1297. X    register int    histcount;
  1298. X    register char    *cp;
  1299. X    static    char    **hist_list = (char **) NULL;
  1300. X
  1301. X    cp = index(list, '\n');
  1302. X    if (cp)
  1303. X        *cp-- = '\0';
  1304. X    histcount = parsit(list, &hist_list);
  1305. X    *array = hist_list;
  1306. X    return (histcount);
  1307. X}
  1308. X
  1309. X
  1310. X/*
  1311. X * get_nglist -- return a nicely set up array of newsgroups
  1312. X * along with a count, when given an NNTP-spec newsgroup list
  1313. X * in the form ng1,ng2,ng...
  1314. X *
  1315. X *    Parameters:        "array" is storage for our array,
  1316. X *                set to point at some static data.
  1317. X *                "list" is the NNTP newsgroup list.
  1318. X *
  1319. X *    Returns:        Number of group specs found.
  1320. X *
  1321. X *    Side effects:        Changes static data area.
  1322. X */
  1323. X
  1324. get_nglist(array, list)
  1325. X    char        ***array;
  1326. X    char        *list;
  1327. X{
  1328. X    register char    *cp;
  1329. X    register int    ngcount;
  1330. X
  1331. X    for (cp = list; *cp != '\0'; ++cp)
  1332. X        if (*cp == ',')
  1333. X            *cp = ' ';
  1334. X
  1335. X    ngcount = parsit(list, array);
  1336. X
  1337. X    return (ngcount);
  1338. X}
  1339. END_OF_FILE
  1340. if test 10834 -ne `wc -c <'./server/newnews.c'`; then
  1341.     echo shar: \"'./server/newnews.c'\" unpacked with wrong size!
  1342. fi
  1343. # end of './server/newnews.c'
  1344. fi
  1345. if test -f './xfer/nntpxfer.c' -a "${1}" != "-c" ; then 
  1346.   echo shar: Will not clobber existing file \"'./xfer/nntpxfer.c'\"
  1347. else
  1348. echo shar: Extracting \"'./xfer/nntpxfer.c'\" \(10068 characters\)
  1349. sed "s/^X//" >'./xfer/nntpxfer.c' <<'END_OF_FILE'
  1350. X/*
  1351. X * nntpxfer
  1352. X *
  1353. X * Connects to the specified nntp server, and transfers all new news
  1354. X * since the last successful invocation.
  1355. X *
  1356. X * last successful invocation date and time are stored in a file at
  1357. X * /usr/spool/news/nntp.<hostname> as 
  1358. X *    groups YYMMDD HHMMSS distributions\n
  1359. X * in case you need to edit it.  You can also override this on 
  1360. X * the command line in the same format, in which case the file won't
  1361. X * be updated.
  1362. X *
  1363. X *    Brian Kantor, UCSD 1986
  1364. X * (some bug fixes by ambar@athena.mit.edu)
  1365. X */
  1366. X
  1367. X#define DEBUG
  1368. X
  1369. X/* you'd think that 4096 articles at one go is enough.... */
  1370. X#define MAXARTS    4096
  1371. X
  1372. X#include <sys/types.h>
  1373. X#include <sys/dir.h>
  1374. X#include <sys/socket.h>
  1375. X#include <sys/stat.h>
  1376. X#include <sys/ioctl.h>
  1377. X#include <sys/file.h>
  1378. X#include <sys/time.h>
  1379. X#include <sys/wait.h>
  1380. X#include <sys/resource.h>
  1381. X
  1382. X#include <net/if.h>
  1383. X#include <netinet/in.h>
  1384. X
  1385. X#include <stdio.h>
  1386. X#include <errno.h>
  1387. X#include <ctype.h>
  1388. X#include <netdb.h>
  1389. X#include <signal.h>
  1390. X#include <dbm.h>
  1391. X
  1392. X#define INEWS    "/usr/lib/news/inews -p"
  1393. X#define HIST    "/usr/lib/news/history"
  1394. X
  1395. char    *malloc();
  1396. char    *strcpy();
  1397. char    *strcat();
  1398. long    time();
  1399. u_long    inet_addr();
  1400. X
  1401. extern int errno;
  1402. char *artlist[MAXARTS];
  1403. int server;            /* stream socket to the nntp server */
  1404. int newart, dupart, misart;
  1405. X
  1406. main(argc, argv)
  1407. int argc;
  1408. char *argv[];
  1409. X    {
  1410. X    FILE *dtfile;        /* where last xfer date/time stored */
  1411. X    char buf[BUFSIZ];
  1412. X    char lastdate[16];
  1413. X    char distributions[BUFSIZ];
  1414. X    char dtname[128];
  1415. X    char newsgroups[BUFSIZ];
  1416. X    char lasttime[16];
  1417. X    int connected = 0;        /* 1 = connected */
  1418. X    int i;
  1419. X    int omitupdate = 0;        /* 1 = don't update datetime */
  1420. X    long clock;
  1421. X    long newdate, newtime;
  1422. X    struct hostent *hp;
  1423. X    struct servent *sp;
  1424. X    struct sockaddr_in sin;
  1425. X    struct tm *now;
  1426. X
  1427. X    /* OPTIONS
  1428. X        argv[1] MUST be the host name
  1429. X        argv[2-4] MAY be "newsgroups YYMMDD HHMMSS"
  1430. X            argv[5] MAY be distributions
  1431. X        (otherwise use 2-4/5 from the file
  1432. X        "/usr/spool/news/nntp.hostname")
  1433. X    */
  1434. X
  1435. X    if (argc != 2 && argc != 5 && argc != 6)
  1436. X        {
  1437. X        (void) printf("Usage: %s host [groups YYMMDD HHMMSS [<dist>]]\n",
  1438. X            argv[0]);
  1439. X        exit(1);
  1440. X        }
  1441. X    
  1442. X    if (argc > 2)
  1443. X        {
  1444. X        omitupdate++;
  1445. X        (void) strcpy(newsgroups, argv[2]);
  1446. X        (void) strcpy(lastdate, argv[3]);
  1447. X        (void) strcpy(lasttime, argv[4]);
  1448. X        (void) strcpy(distributions, "");
  1449. X        if (argc > 5)
  1450. X            (void) strcpy(distributions, argv[5]);
  1451. X        }
  1452. X    else
  1453. X        {
  1454. X        (void) strcpy(dtname, "/usr/spool/news/nntp.");
  1455. X        (void) strcat(dtname, argv[1]);
  1456. X        dtfile = fopen(dtname, "r");
  1457. X        if (dtfile == NULL)
  1458. X            {
  1459. X            (void) printf("%s not found; using * 860101 000000 \n", 
  1460. X                dtname);
  1461. X            (void) strcpy(newsgroups, "*");
  1462. X            (void) strcpy(lastdate, "860101");
  1463. X            (void) strcpy(lasttime, "000000");
  1464. X            (void) strcpy(distributions, "");
  1465. X            }
  1466. X        else
  1467. X            {
  1468. X            if (fscanf(dtfile, "%s %s %s %s",
  1469. X                newsgroups, lastdate, lasttime, distributions) < 3)
  1470. X                {
  1471. X                (void) printf("%s invalid; using * 860101 000000\n",
  1472. X                    dtname);
  1473. X                (void) strcpy(newsgroups, "*");
  1474. X                (void) strcpy(lastdate, "860101");
  1475. X                (void) strcpy(lasttime, "000000");
  1476. X                (void) strcpy(distributions, "");
  1477. X                }
  1478. X            (void) fclose(dtfile);
  1479. X            }
  1480. X        clock = time((long *)0);
  1481. X        now = gmtime(&clock);
  1482. X        newdate = (now->tm_year * 10000) +
  1483. X            ((now->tm_mon + 1) * 100) + now->tm_mday;
  1484. X        newtime = (now->tm_hour * 10000) +
  1485. X            (now->tm_min * 100) + now->tm_sec;
  1486. X        }
  1487. X
  1488. X#ifdef DEBUG
  1489. X    (void) printf("newsgroups = '%s'\n", newsgroups);
  1490. X    (void) printf("date = '%s'\n", lastdate);
  1491. X    (void) printf("time = '%s'\n", lasttime);
  1492. X    (void) printf("distributions = '%s'\n", distributions);
  1493. X    (void) printf("now is = %06d %06d\n", newdate, newtime);
  1494. X#endif
  1495. X
  1496. X    if (dbminit(HIST) < 0)
  1497. X        {
  1498. X        perror("couldn't open history file");
  1499. X        exit(1);
  1500. X        }
  1501. X
  1502. X    sin.sin_addr.s_addr = inet_addr(argv[1]);
  1503. X    if (sin.sin_addr.s_addr != -1) 
  1504. X        {
  1505. X        sin.sin_family = AF_INET;
  1506. X        }
  1507. X    else 
  1508. X        {
  1509. X        hp = gethostbyname(argv[1]);
  1510. X        if (hp == NULL) 
  1511. X            {
  1512. X            (void) printf("%s: unknown host\n", argv[1]);
  1513. X            exit(1);
  1514. X            }
  1515. X
  1516. X        sin.sin_family = hp->h_addrtype;
  1517. X#ifdef    BSD43
  1518. X        bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
  1519. X            hp->h_length);
  1520. X#else    BSD43
  1521. X        bcopy(hp->h_addr, (caddr_t)&sin.sin_addr,
  1522. X            hp->h_length);
  1523. X#endif    BSD43
  1524. X        }
  1525. X    
  1526. X    sp = getservbyname("nntp", "tcp");
  1527. X    if (sp == NULL)
  1528. X        {
  1529. X        perror("nntp/tcp");
  1530. X        exit(1);
  1531. X        }
  1532. X
  1533. X    sin.sin_port = sp->s_port;
  1534. X
  1535. X    do    {
  1536. X        server = socket(AF_INET, SOCK_STREAM, 0);
  1537. X        if (server < 0) 
  1538. X            {
  1539. X            perror("nntpxfer: socket");
  1540. X            exit(1);
  1541. X            }
  1542. X
  1543. X        if (connect(server, (struct sockaddr *)&sin, sizeof (sin)) < 0) 
  1544. X            {
  1545. X#ifdef    BSD43
  1546. X            if (hp && hp->h_addr_list[1]) 
  1547. X                {
  1548. X                hp->h_addr_list++;
  1549. X                bcopy(hp->h_addr_list[0],
  1550. X                    (caddr_t)&sin.sin_addr, hp->h_length);
  1551. X                (void) close(server);
  1552. X                continue;
  1553. X                }
  1554. X#endif    BSD43
  1555. X            perror("nntpxfer: connect");
  1556. X            exit(1);
  1557. X            }
  1558. X        connected++;
  1559. X        }
  1560. X    while (connected == 0);
  1561. X
  1562. X#ifdef DEBUG
  1563. X    (void) printf("connected to nntp server at %s\n", argv[1]);
  1564. X#endif
  1565. X    /*
  1566. X    * ok, at this point we're connected to the nntp daemon 
  1567. X    * at the distant host.
  1568. X    */
  1569. X
  1570. X    /* get the greeting herald */
  1571. X    (void) sockread(buf);
  1572. X#ifdef DEBUG
  1573. X    (void) printf("%s\n", buf);
  1574. X#endif
  1575. X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  1576. X        {
  1577. X        (void) printf("protocol error: got '%s'\n", buf);
  1578. X        (void) close(server);
  1579. X        exit(1);
  1580. X        }
  1581. X
  1582. X
  1583. X    /* first, tell them we're a slave process to get priority */
  1584. X    sockwrite("SLAVE");
  1585. X    (void) sockread(buf);
  1586. X#ifdef DEBUG
  1587. X    (void) printf("%s\n", buf);
  1588. X#endif
  1589. X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  1590. X        {
  1591. X        (void) printf("protocol error: got '%s'\n", buf);
  1592. X        (void) close(server);
  1593. X        exit(1);
  1594. X        }
  1595. X    
  1596. X    /* now, ask for a list of new articles */
  1597. X    if (strlen(distributions))
  1598. X        (void) sprintf(buf,"NEWNEWS %s %s %s GMT <%s>", 
  1599. X            newsgroups, lastdate, lasttime, distributions);
  1600. X    else
  1601. X        (void) sprintf(buf,"NEWNEWS %s %s %s GMT", 
  1602. X            newsgroups, lastdate, lasttime);
  1603. X    sockwrite(buf);
  1604. X    (void) sockread(buf);
  1605. X#ifdef DEBUG
  1606. X    (void) printf("%s\n", buf);
  1607. X#endif
  1608. X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  1609. X        {
  1610. X        (void) printf("protocol error: got '%s'\n", buf);
  1611. X        (void) close(server);
  1612. X        exit(1);
  1613. X        }
  1614. X    /* and here comes the list, terminated with a "." */
  1615. X#ifdef DEBUG
  1616. X    (void) printf("data\n");
  1617. X#endif
  1618. X    while (1)
  1619. X        {
  1620. X        (void) sockread(buf);
  1621. X        if (!strcmp(buf,"."))
  1622. X            break;
  1623. X        if (wewant(buf))
  1624. X            {
  1625. X            if (newart > MAXARTS)
  1626. X                {
  1627. X                omitupdate++;
  1628. X                continue;
  1629. X                }
  1630. X            artlist[newart] = malloc((unsigned)(strlen(buf)+1));
  1631. X            (void) strcpy(artlist[newart], buf);
  1632. X            newart++;
  1633. X            }
  1634. X        else
  1635. X            dupart++;
  1636. X        }
  1637. X#ifdef DEBUG
  1638. X    (void) printf(".\n%d new, %d dup articles\n", newart, dupart);
  1639. X#endif
  1640. X
  1641. X    /* now that we know which articles we want, retrieve them */
  1642. X    for (i=1; i < newart; i++)
  1643. X        (void) artfetch(artlist[i]);
  1644. X
  1645. X#ifdef DEBUG
  1646. X    (void) printf("%d missing articles\n", misart);
  1647. X#endif
  1648. X    /* we're all done, so tell them goodbye */
  1649. X    sockwrite("QUIT");
  1650. X    (void) sockread(buf);
  1651. X#ifdef DEBUG
  1652. X    (void) printf("%s\n", buf);
  1653. X#endif
  1654. X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  1655. X        {
  1656. X        (void) printf("error: got '%s'\n", buf);
  1657. X        (void) close(server);
  1658. X        exit(1);
  1659. X        }
  1660. X    (void) close(server);
  1661. X
  1662. X    /* do we want to update the timestamp file? */
  1663. X    if (!omitupdate)
  1664. X        {
  1665. X        (void) sprintf(buf, "%s %06d %06d %s\n",
  1666. X            newsgroups, newdate, newtime, distributions);
  1667. X#ifdef DEBUG
  1668. X        (void) printf("updating %s:\n\t%s\n", dtname, buf);
  1669. X#endif
  1670. X        dtfile = fopen(dtname, "w");
  1671. X        if (dtfile == NULL)
  1672. X            {
  1673. X            perror(dtname);
  1674. X            exit(1);
  1675. X            }
  1676. X        (void) fputs(buf,dtfile);
  1677. X        (void) fclose(dtfile);
  1678. X        }
  1679. X    exit(0);
  1680. X}
  1681. X
  1682. artfetch(articleid)
  1683. char *articleid;
  1684. X    {
  1685. X    int lines = 0;
  1686. X    char buf[BUFSIZ];
  1687. X    FILE *inews;
  1688. X
  1689. X    /* now, ask for the article */
  1690. X    (void) sprintf(buf,"ARTICLE %s", articleid);
  1691. X    sockwrite(buf);
  1692. X    (void) sockread(buf);
  1693. X#ifdef DEBUG
  1694. X    (void) printf("%s\n", buf);
  1695. X#endif
  1696. X    if (buf[0] == '4')    /* missing article, just skipit */
  1697. X        {
  1698. X        misart++;
  1699. X        return(0);
  1700. X        }
  1701. X
  1702. X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  1703. X        {
  1704. X        (void) printf("protocol error: got '%s'\n", buf);
  1705. X        (void) close(server);
  1706. X        exit(1);
  1707. X        }
  1708. X#ifdef DEBUG
  1709. X    (void) printf("command: %s\n", INEWS);
  1710. X#endif
  1711. X    if ( (inews = popen(INEWS, "w")) == NULL)
  1712. X        {
  1713. X        perror(INEWS);
  1714. X        exit(1);
  1715. X        }
  1716. X
  1717. X    /* and here comes the article, terminated with a "." */
  1718. X#ifdef DEBUG
  1719. X    (void) printf("data\n");
  1720. X#endif
  1721. X    while (1)
  1722. X        {
  1723. X        (void) sockread(buf);
  1724. X        if (buf[0] == '.' && buf[1] == '\0')
  1725. X            break;
  1726. X        lines++;
  1727. X        (void) strcat(buf,"\n");
  1728. X        (void) fputs(((buf[0] == '.') ? buf + 1 : buf),
  1729. X               inews);
  1730. X        }
  1731. X#ifdef DEBUG
  1732. X    (void) printf(".\n%d lines\n", lines);
  1733. X#endif
  1734. X    (void) fflush(inews);
  1735. X    (void) pclose(inews);
  1736. X    return(0);
  1737. X        }
  1738. X
  1739. int
  1740. sockread(buf)
  1741. char *buf;
  1742. X    {
  1743. X    char c;
  1744. X    int j = 0;
  1745. X#ifdef BSD43
  1746. X    fd_set rf;
  1747. X#else BSD43
  1748. X    int rf;
  1749. X#endif BSD43
  1750. X    struct timeval tv;
  1751. X    int r;
  1752. X    char *p = buf;
  1753. X
  1754. X    while ( 1 )
  1755. X        {
  1756. X        tv.tv_sec = 1800;    /* 15 minutes */
  1757. X        tv.tv_usec = 0L;
  1758. X#ifdef BSD43
  1759. X        FD_ZERO(&rf);
  1760. X        FD_SET(server, &rf);
  1761. X#else BSD43
  1762. X        rf = 1 << server;
  1763. X#endif BSD43
  1764. X        r = select(20, (fd_set *)&rf, (fd_set *)0, (fd_set *)&rf, &tv);
  1765. X
  1766. X        if (r < 0)
  1767. X            {
  1768. X            if (errno == EINTR)
  1769. X                continue;
  1770. X            perror("getsock select");
  1771. X            exit(1);
  1772. X            }
  1773. X        if (r == 0)
  1774. X            {
  1775. X            printf("read timed out.\n");
  1776. X            exit(1);
  1777. X            }
  1778. X
  1779. X        if (read(server, &c, 1) <= 0)
  1780. X            break;
  1781. X
  1782. X        /* mask off any chance parity bits */
  1783. X        *p = c & 0x7f;
  1784. X
  1785. X        /* look for end of line (== LF) */
  1786. X        if (c == 0x0a)
  1787. X            {
  1788. X            if (j > 0 && *(p-1) == 0x0d)
  1789. X                *(p-1) = '\0';
  1790. X            else
  1791. X                *p = '\0';
  1792. X            return(strlen(buf));
  1793. X            }
  1794. X        j++; p++;
  1795. X        }
  1796. X    perror("sockread");
  1797. X    (void) close(server);
  1798. X    exit(1);
  1799. X    /* NOTREACHED */
  1800. X    }
  1801. X
  1802. sockwrite(buf)
  1803. char *buf;
  1804. X    {
  1805. X    register int sz;
  1806. X    char buf2[BUFSIZ];
  1807. X#ifdef DEBUG
  1808. X    (void) printf(">>> %s\n", buf);
  1809. X#endif
  1810. X    (void) strcpy(buf2,buf);
  1811. X    (void) strcat(buf2,"\r\n");
  1812. X    sz = strlen(buf2);
  1813. X    if (write(server,buf2,sz) != sz)
  1814. X        {
  1815. X        (void) printf("write error on server socket\n");
  1816. X        (void) close(server);
  1817. X        exit(1);
  1818. X        }
  1819. X    }
  1820. X
  1821. int
  1822. wewant(articleid)
  1823. char *articleid;
  1824. X    {
  1825. X    datum k, d;
  1826. X    char id[BUFSIZ];
  1827. X    char *p;
  1828. X
  1829. X    /* remove any case sensitivity */
  1830. X    (void) strcpy(id, articleid);
  1831. X    p = id;
  1832. X    while (*p)
  1833. X        {
  1834. X        if (isupper(*p))
  1835. X            *p = tolower(*p);
  1836. X        p++;
  1837. X        }
  1838. X
  1839. X    k.dptr = id;
  1840. X    k.dsize = strlen(articleid) + 1;
  1841. X
  1842. X    d = fetch(k);
  1843. X
  1844. X    if (d.dptr)
  1845. X        {
  1846. X#ifdef DEBUG
  1847. X        (void) printf("dup: '%s'\n", articleid);
  1848. X#endif
  1849. X        return(0);
  1850. X        }
  1851. X
  1852. X#ifdef DEBUG
  1853. X    (void) printf("new: '%s'\n", articleid);
  1854. X#endif
  1855. X    return(1);
  1856. X    }
  1857. END_OF_FILE
  1858. if test 10068 -ne `wc -c <'./xfer/nntpxfer.c'`; then
  1859.     echo shar: \"'./xfer/nntpxfer.c'\" unpacked with wrong size!
  1860. fi
  1861. # end of './xfer/nntpxfer.c'
  1862. fi
  1863. if test -f './xmit/remote.c' -a "${1}" != "-c" ; then 
  1864.   echo shar: Will not clobber existing file \"'./xmit/remote.c'\"
  1865. else
  1866. echo shar: Extracting \"'./xmit/remote.c'\" \(9250 characters\)
  1867. sed "s/^X//" >'./xmit/remote.c' <<'END_OF_FILE'
  1868. X/*
  1869. X** remote communication routines for NNTP/SMTP style communication.
  1870. X**
  1871. X**    sendcmd        - return TRUE on error.
  1872. X**
  1873. X**    readreply    - return reply code or FAIL for error;
  1874. X**                modifies buffer passed to it.
  1875. X**
  1876. X**    converse    - sendcmd() & readreply();
  1877. X**                return reply code or FAIL for error;
  1878. X**                modifies buffer passed to it.
  1879. X**
  1880. X**    hello        - establish connection with remote;
  1881. X**                check greeting code.
  1882. X**
  1883. X**    goodbye        - give QUIT command, and shut down connection.
  1884. X**
  1885. X**    sfgets        - safe fgets(); does fgets with TIMEOUT.
  1886. X**              (N.B.: possibly unportable stdio macro ref in here)
  1887. X**
  1888. X**    rfgets        - remote fgets() (calls sfgets());
  1889. X**                does SMTP dot escaping and
  1890. X**                \r\n -> \n conversion.
  1891. X**
  1892. X**    sendfile    - send a file with SMTP dot escaping and
  1893. X**                \n -> \r\n conversion.
  1894. X**
  1895. X** Erik E. Fair <fair@ucbarpa.berkeley.edu>
  1896. X*/
  1897. X
  1898. X#include "nntpxmit.h"
  1899. X#include <sys/types.h>
  1900. X#include <sys/socket.h>
  1901. X#include <errno.h>
  1902. X#include <stdio.h>
  1903. X#include <ctype.h>
  1904. X#include <setjmp.h>
  1905. X#include <signal.h>
  1906. X#ifdef SYSLOG
  1907. X#include <syslog.h>
  1908. X#endif
  1909. X#include "get_tcp_conn.h"
  1910. X#include "nntp.h"
  1911. X
  1912. static    jmp_buf    SFGstack;
  1913. FILE    *rmt_rd;
  1914. FILE    *rmt_wr;
  1915. char    *sfgets();
  1916. char    *rfgets();
  1917. X
  1918. extern    int    errno;
  1919. extern    char    Debug;
  1920. extern    char    *errmsg();
  1921. extern    char    *strcpy();
  1922. extern    void    log();
  1923. X
  1924. X/*
  1925. X** send cmd to remote, terminated with a CRLF.
  1926. X*/
  1927. sendcmd(cmd)
  1928. char    *cmd;
  1929. X{
  1930. X    if (cmd == (char *)NULL)
  1931. X        return(TRUE);    /* error */
  1932. X    dprintf(stderr, ">>> %s\n", cmd);    /* DEBUG */
  1933. X    (void) fprintf(rmt_wr, "%s\r\n", cmd);
  1934. X    (void) fflush(rmt_wr);
  1935. X    return(ferror(rmt_wr));
  1936. X}
  1937. X
  1938. X/*
  1939. X** read a reply line from the remote server and return the code number
  1940. X** as an integer, and the message in a buffer supplied by the caller.
  1941. X** Returns FAIL if something went wrong.
  1942. X*/
  1943. readreply(buf, size)
  1944. register char    *buf;
  1945. int    size;
  1946. X{
  1947. X    register char    *cp;
  1948. X    register int    len;
  1949. X
  1950. X    if (buf == (char *)NULL || size <= 0)
  1951. X        return(FAIL);
  1952. X
  1953. X    /*
  1954. X    ** make sure it's invalid, unless we say otherwise
  1955. X    */
  1956. X    buf[0] = '\0';
  1957. X
  1958. X    /*
  1959. X    ** read one line from the remote
  1960. X    */
  1961. X    if (sfgets(buf, size, rmt_rd) == NULL)
  1962. X        return(FAIL);    /* error reading from remote */
  1963. X
  1964. X    /*
  1965. X    ** Make sure that what the remote sent us had a CRLF at the end
  1966. X    ** of the line, and then null it out.
  1967. X    */
  1968. X    if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r' &&
  1969. X        *(cp + 1) == '\n')
  1970. X    {
  1971. X        *cp = '\0';
  1972. X    } else
  1973. X        return(FAIL);    /* error reading from remote */
  1974. X
  1975. X    dprintf(stderr, "%s\n", buf);    /* DEBUG */
  1976. X    /*
  1977. X    ** Skip any non-digits leading the response code 
  1978. X    ** and then convert the code from ascii to integer for
  1979. X    ** return from this routine.
  1980. X    */
  1981. X    cp = buf;
  1982. X    while(*cp != '\0' && isascii(*cp) && !isdigit(*cp))
  1983. X        cp++;    /* skip anything leading */
  1984. X
  1985. X    if (*cp == '\0' || !isascii(*cp))
  1986. X        return(FAIL);    /* error reading from remote */
  1987. X
  1988. X    return(atoi(cp));
  1989. X}
  1990. X
  1991. X/*
  1992. X** send a command to the remote, and wait for a response
  1993. X** returns the response code, and the message in the buffer
  1994. X*/
  1995. converse(buf, size)
  1996. char    *buf;
  1997. int    size;
  1998. X{
  1999. X    register int    resp;
  2000. X
  2001. X    if (sendcmd(buf))
  2002. X        return(FAIL);    /* Ooops! Something went wrong in xmit */
  2003. X    /*
  2004. X    ** Skip the silly 100 series messages, since they're not the
  2005. X    ** final response we can expect
  2006. X    */
  2007. X    while((resp = readreply(buf, size)) >= 100 && resp < 200)
  2008. X        continue;
  2009. X    return(resp);
  2010. X}
  2011. X
  2012. X/*
  2013. X** Contact the remote server and set up the two global FILE pointers
  2014. X** to that descriptor.
  2015. X**
  2016. X** I can see the day when this routine will have 8 args:  one for
  2017. X** hostname, and one for each of the seven ISO Reference Model layers
  2018. X** for networking. A curse upon those involved with the ISO protocol
  2019. X** effort: may they be forced to use the network that they will create,
  2020. X** as opposed to something that works (like the Internet).
  2021. X*/
  2022. hello(host, transport)
  2023. char    *host;
  2024. int    transport;
  2025. X{ char    *service;
  2026. X    char    *rmode = "r";
  2027. X    char    *wmode = "w";
  2028. X    char    *e_fdopen = "fdopen(%d, \"%s\"): %s";
  2029. X    int    socket0, socket1;    /* to me (bad pun) */
  2030. X    char    buf[BUFSIZ];
  2031. X
  2032. X    switch(transport) {
  2033. X    case T_IP_TCP:
  2034. X        service = "nntp";
  2035. X        socket0 = get_tcp_conn(host, service);
  2036. X        break;
  2037. X    case T_DECNET:
  2038. X#ifdef DECNET
  2039. X        (void) signal(SIGPIPE, SIG_IGN);
  2040. X        service = "NNTP";
  2041. X        socket0 = dnet_conn(host, service, 0, 0, 0, 0, 0);
  2042. X        if (socket0 < 0) {
  2043. X            switch(errno) {
  2044. X            case EADDRNOTAVAIL:
  2045. X                socket0 = NOHOST;
  2046. X                break;
  2047. X            case ESRCH:
  2048. X                socket0 = NOSERVICE;
  2049. X                break;
  2050. X            }
  2051. X        }
  2052. X        break;
  2053. X#else
  2054. X        log(L_WARNING, "no DECNET support compiled in");
  2055. X        return(FAIL);
  2056. X#endif
  2057. X    case T_FD:
  2058. X        service = "with a smile";
  2059. X        socket0 = atoi(host);
  2060. X        break;
  2061. X    }
  2062. X
  2063. X    if (socket0 < 0) {
  2064. X        switch(socket0) {
  2065. X        case NOHOST:
  2066. X            sprintf(buf, "%s host unknown", host);
  2067. X            log(L_WARNING, buf);
  2068. X            return(FAIL);
  2069. X        case NOSERVICE:
  2070. X            sprintf(buf, "%s service unknown: %s", host, service);
  2071. X            log(L_WARNING, buf);
  2072. X            return(FAIL);
  2073. X        case FAIL:
  2074. X            sprintf(buf, "%s hello: %s", host, errmsg(errno));
  2075. X            log(L_NOTICE, buf);
  2076. X            return(FAIL);
  2077. X        }
  2078. X    }
  2079. X
  2080. X    if ((socket1 = dup(socket0)) < 0) {
  2081. X        sprintf(buf, "dup(%d): %s", socket0, errmsg(errno));
  2082. X        log(L_WARNING, buf);
  2083. X        (void) close(socket0);
  2084. X        return(FAIL);
  2085. X    }
  2086. X
  2087. X    if ((rmt_rd = fdopen(socket0, rmode)) == (FILE *)NULL) {
  2088. X        sprintf(buf, e_fdopen, socket0, rmode);
  2089. X        log(L_WARNING, buf);
  2090. X        (void) close(socket0);
  2091. X        (void) close(socket1);
  2092. X        return(FAIL);
  2093. X    }
  2094. X
  2095. X    if ((rmt_wr = fdopen(socket1, wmode)) == (FILE *)NULL) {
  2096. X        sprintf(buf, e_fdopen, socket1, wmode);
  2097. X        log(L_WARNING, buf);
  2098. X        (void) fclose(rmt_rd);
  2099. X        rmt_rd = (FILE *)NULL;
  2100. X        (void) close(socket1);
  2101. X        return(FAIL);
  2102. X    }
  2103. X
  2104. X    switch(readreply(buf, sizeof(buf))) {
  2105. X    case OK_CANPOST:
  2106. X    case OK_NOPOST:
  2107. X        if (ferror(rmt_rd)) {
  2108. X            goodbye(DONT_WAIT);
  2109. X            return(FAIL);
  2110. X        }
  2111. X        break;
  2112. X    default:
  2113. X        if (buf[0] != '\0') {
  2114. X            char    err[BUFSIZ];
  2115. X
  2116. X            sprintf(err, "%s greeted us with %s", host, buf);
  2117. X            log(L_NOTICE, err);
  2118. X        }
  2119. X        goodbye(DONT_WAIT);
  2120. X        return(FAIL);
  2121. X    }
  2122. X    return(NULL);
  2123. X}
  2124. X
  2125. X/*
  2126. X** Say goodbye to the nice remote server.
  2127. X**
  2128. X** We trap SIGPIPE because the socket might already be gone.
  2129. X*/
  2130. goodbye(wait_for_reply)
  2131. int    wait_for_reply;
  2132. X{
  2133. X    register ifunp    pstate = signal(SIGPIPE, SIG_IGN);
  2134. X
  2135. X    if (sendcmd("QUIT"))
  2136. X        wait_for_reply = FALSE;    /* override, something's wrong. */
  2137. X    /*
  2138. X    ** I don't care what they say to me; this is just being polite.
  2139. X    */
  2140. X    if (wait_for_reply) {
  2141. X        char    buf[BUFSIZ];
  2142. X
  2143. X        (void) readreply(buf, sizeof(buf));
  2144. X    }
  2145. X    (void) fclose(rmt_rd);
  2146. X    rmt_rd = (FILE *)NULL;
  2147. X    (void) fclose(rmt_wr);
  2148. X    rmt_wr = (FILE *)NULL;
  2149. X    if (pstate != (ifunp)(-1));
  2150. X        (void) signal(SIGPIPE, pstate);
  2151. X}
  2152. X
  2153. static
  2154. to_sfgets()
  2155. X{
  2156. X    longjmp(SFGstack, 1);
  2157. X}
  2158. X
  2159. X/*
  2160. X** `Safe' fgets, ala sendmail. This fgets will timeout after some
  2161. X** period of time, on the assumption that if the remote did not
  2162. X** return, they're gone.
  2163. X** WARNING: contains a possibly unportable reference to stdio
  2164. X** error macros.
  2165. X*/
  2166. char *
  2167. sfgets(buf, size, fp)
  2168. char    *buf;
  2169. int    size;
  2170. FILE    *fp;
  2171. X{
  2172. X    register char    *ret;
  2173. X    int    esave;
  2174. X
  2175. X    if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
  2176. X        return((char *)NULL);
  2177. X    if (setjmp(SFGstack)) {
  2178. X        (void) alarm(0);        /* reset alarm clock */
  2179. X        (void) signal(SIGALRM, SIG_DFL);
  2180. X#ifdef apollo
  2181. X        fp->_flag |= _SIERR;
  2182. X#else
  2183. X        fp->_flag |= _IOERR;        /* set stdio error */
  2184. X#endif
  2185. X#ifndef ETIMEDOUT
  2186. X        errno = EPIPE;            /* USG doesn't have ETIMEDOUT */
  2187. X#else
  2188. X        errno = ETIMEDOUT;        /* connection timed out */
  2189. X#endif
  2190. X        return((char *)NULL);        /* bad read, remote time out */
  2191. X    }
  2192. X    (void) signal(SIGALRM, to_sfgets);
  2193. X    (void) alarm(TIMEOUT);
  2194. X    ret = fgets(buf, size, fp);
  2195. X    esave = errno;
  2196. X    (void) alarm(0);            /* reset alarm clock */
  2197. X    (void) signal(SIGALRM, SIG_DFL);    /* reset SIGALRM */
  2198. X    errno = esave;
  2199. X    return(ret);
  2200. X}
  2201. X
  2202. X/*
  2203. X** Remote fgets - converts CRLF to \n, and returns NULL on `.' EOF from
  2204. X** the remote. Otherwise it returns its first argument, like fgets(3).
  2205. X*/
  2206. char *
  2207. rfgets(buf, size, fp)
  2208. char    *buf;
  2209. int    size;
  2210. FILE    *fp;
  2211. X{
  2212. X    register char    *cp = buf;
  2213. X    register int    len;
  2214. X
  2215. X    if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
  2216. X        return((char *)NULL);
  2217. X    *cp = '\0';
  2218. X    if (sfgets(buf, size, fp) == (char *)NULL)
  2219. X        return((char *)NULL);
  2220. X
  2221. X    /* <CRLF> => '\n' */
  2222. X    if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r') {
  2223. X        *cp++ = '\n';
  2224. X        *cp = '\0';
  2225. X    }
  2226. X
  2227. X    /* ".\n" => EOF */
  2228. X    cp = buf;
  2229. X    if (*cp++ == '.' && *cp == '\n') {
  2230. X        return((char *)NULL);    /* EOF */
  2231. X    }
  2232. X
  2233. X    /* Dot escaping */
  2234. X    if (buf[0] == '.')
  2235. X        (void) strcpy(&buf[0], &buf[1]);
  2236. X    return(buf);
  2237. X}
  2238. X
  2239. X/*
  2240. X** send the contents of an open file descriptor to the remote,
  2241. X** with appropriate RFC822 filtering (e.g. CRLF line termination,
  2242. X** and dot escaping). Return FALSE if something went wrong.
  2243. X*/
  2244. sendfile(fp)
  2245. FILE    *fp;
  2246. X{
  2247. X    register int    c;
  2248. X    register FILE    *remote = rmt_wr;
  2249. X    register int    nl = TRUE;    /* assume we start on a new line */
  2250. X
  2251. X/*
  2252. X** I'm using putc() instead of fputc();
  2253. X** why do a subroutine call when you don't have to?
  2254. X** Besides, this ought to give the C preprocessor a work-out.
  2255. X*/
  2256. X#define    PUTC(c)    if (putc(c, remote) == EOF) return(FALSE)
  2257. X
  2258. X    if (fp == (FILE *)NULL)
  2259. X        return(FALSE);
  2260. X
  2261. X    /*
  2262. X    ** the second test makes no sense to me,
  2263. X    ** but System V apparently needed it...
  2264. X    */
  2265. X    while((c = fgetc(fp)) != EOF && !feof(fp)) {
  2266. X        switch(c) {
  2267. X        case '\n':
  2268. X            PUTC('\r');        /* \n -> \r\n */
  2269. X            PUTC(c);
  2270. X            nl = TRUE;        /* for dot escaping */
  2271. X            break;
  2272. X        case '.':
  2273. X            if (nl) {
  2274. X                PUTC(c);    /* add a dot */
  2275. X                nl = FALSE;
  2276. X            }
  2277. X            PUTC(c);
  2278. X            break;
  2279. X        default:
  2280. X            PUTC(c);
  2281. X            nl = FALSE;
  2282. X            break;
  2283. X        }
  2284. X    }
  2285. X    if (!nl) {
  2286. X        PUTC('\r');
  2287. X        PUTC('\n');
  2288. X    }
  2289. X    return( !(sendcmd(".") || ferror(fp)) );
  2290. X}
  2291. END_OF_FILE
  2292. if test 9250 -ne `wc -c <'./xmit/remote.c'`; then
  2293.     echo shar: \"'./xmit/remote.c'\" unpacked with wrong size!
  2294. fi
  2295. # end of './xmit/remote.c'
  2296. fi
  2297. echo shar: End of archive 6 \(of 9\).
  2298. cp /dev/null ark6isdone
  2299. MISSING=""
  2300. for I in 1 2 3 4 5 6 7 8 9 ; do
  2301.     if test ! -f ark${I}isdone ; then
  2302.     MISSING="${MISSING} ${I}"
  2303.     fi
  2304. done
  2305. if test "${MISSING}" = "" ; then
  2306.     echo You have unpacked all 9 archives.
  2307.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2308. else
  2309.     echo You still need to unpack the following archives:
  2310.     echo "        " ${MISSING}
  2311. fi
  2312. ##  End of shell archive.
  2313. exit 0
  2314.